/*
 * smarthome.c
 *
 *  Created on: 2011-10-29
 *      Author: poseidon
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "types.h"
#include "define.h"
#include "net.h"
#include "thread.h"
#include "user_examine.h"

#define RECV_TIME_OUT		2000

int is_connected[25+MAX_CONNECTED_NO];

#define IS_CONNECTED(a)	is_connected[25+a]

//请求处理线程，循环处理请求，当请求要退出时，关闭描述符，设置连接为未连接。
pvoid request_process(void *arg) {
	int fd = *((int *)arg);
	ctl_hdr *rcv_hdr;
	char buffer[256];
	int rcv_len = 0;
	unsigned char ret_code = 0;

	struct timeval tm_out;
	tm_out.tv_sec = RECV_TIME_OUT;
	tm_out.tv_usec = 0;

	if ((setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tm_out, sizeof(tm_out))) < 0) {
		perror("setsockopt");
		exit(-1);
	}

	do {
		sleep(3);
		bzero(buffer, sizeof(buffer));
		rcv_len = readn(fd, buffer, sizeof(buffer));
		printf("rcv_len is %d \n", rcv_len);
		if (rcv_len < 0) {
			printf("socket %d timout \n", fd);
			break;
		}
		if (rcv_len > 0) {
			rcv_hdr = (ctl_hdr)buffer;
			if (rcv_hdr.ki == KI_LOGOFF) {
				ret_code = RPL_LOGOFF;
			} else {
				ret_code = proc_cmd(buffer, fd);
			}
			printf("proc_cmd return value is %d\n", ret_code);

			struct replay_packet replay;
			replay.head.len = 1;
			replay.head.encrpyt = ENCRPYT_NO;
			replay.head.mo = MO_SERVER;
			replay.head.ttl = 0;
			replay.head.extent = 0;
			replay.data = ret_code;
			writen(fd, &replay, sizeof(replay));
		}

	} while (ret_code != RPL_LOGOFF);

	close(fd);
	IS_CONNECTED(fd) = 0;
	return 0;
}


//智能家居主线程
pvoid smarthome(void *args) {
	int acceptfd, fd, listenfd;
	fd_set readfds, exceptfds;
	struct sockaddr_in addr;
	socklen_t addr_len = sizeof(struct sockaddr_in);
	char buffer_in[256];
	struct replay_packet replay;

	ctl_hdr *hdr;
	int hdr_len = sizeof(hdr);

	struct timeval timeout;
	timeout.tv_sec = 1;
	timeout.tv_usec = 0;

	listenfd = *((int *)args);

	//清零计数数组
	for (fd = 0; fd < MAX_CONNECTED; fd ++) {
		IS_CONNECTED(fd) = 0;
	}
	//设置当前sockfd为连接
	IS_CONNECTED(listenfd) = 1;

	Pthreadstruct sock_thread_struct;

	while (1) {
		sleep(1);
		FD_ZERO(&readfds);
		FD_ZERO(&exceptfds);

		//把所有连接的描述符添加到select的检测集中
		for (fd = 3; fd < MAX_CONNECTED; fd ++) {
			if (IS_CONNECTED(fd)) {
				FD_SET(fd, &readfds);
				FD_SET(fd, &exceptfds);
			}
		}

		//调用select检测是否有 可用描述符
		if (select(MAX_CONNECTED, &readfds, NULL, &exceptfds, &timeout) < 0) {
			perror("select");
			continue;
		}
		//判断不同的集合中是否有需要处理的描述符
		for (fd = 3; fd < MAX_CONNECTED; fd ++) {
			//对异常描述符集的处理
			if (FD_ISSET(fd, &exceptfds)) {
				if (listenfd != fd) {
					printf("exceptfds connection closed \n");
					close(fd);
					IS_CONNECTED(fd) = 0;
				}
			}

			//对读集的处理
			if (FD_ISSET(fd, &readfds)) {
				//如果是监听描述符，就接收连接
				if (listenfd == fd) {
					if ((acceptfd = accept(listenfd, (struct sockaddr *)&addr, &addr_len)) < 0) {
						perror("accept");
					} else {
						printf("Connect from %s sock: %d\n", inet_ntoa(addr.sin_addr), acceptfd);
						if (acceptfd < MAX_CONNECTED_NO) {
							IS_CONNECTED(acceptfd) = 1;
						} else {
							close(acceptfd);
						}
					}
					//如果不是监听描述符,接受数据
				} else {
					bzero(buffer_in, sizeof(buffer_in));
					int rec_len = 0;

					//如果当前是非法连接，就关闭连接
					if (IS_CONNECTED(fd) == 2) {
						printf("readfds connection closed. \n");
						close(fd);
						IS_CONNECTED(fd) = 0;
					} else {
						//否则，就接收客户端的请求
						rec_len = readn(fd, buffer_in, sizeof(buffer_in));
						if (rec_len > 0) {
							bzero(&replay, sizeof(replay));

							replay.head.len = 1;
							replay.head.encrpyt = ENCRPYT_NO;
							replay.head.mo = MO_SERVER;
							replay.head.ttl = 0;
							replay.head.extent = 0;
							replay.head.ki = KI_REPLAY;

							hdr = (ctl_hdr)buffer_in;
							int data_len = (int)hdr.len;
							char *data;
							data = (char *)buffer_in + hdr_len;
							struct user * user_struct;
							memcpy(user_struct, data, sizeof(struct user));
							switch (hdr.ki) {
							case KI_REGISTER:
								//如果是注册的请求报文
								if (user_register(user_struct) == 0) {
									//注册成功
									replay.data = RPL_REGISTER_SUCCESS;
									writen(fd, (void *)&replay, sizeof(replay));
									printf("Check User successful\n");
									tcp_close(fd);
									IS_CONNECTED(fd) = 0;
								} else {
									replay.data = RPL_REGISTER_FALLED;
									writen(fd, (void *)&replay, sizeof(replay));
									IS_CONNECTED(fd) = 1;
								}
								break;
							case KI_LOGIN:
								if (user_check(user_struct) == 0) {
									//登录成功
									replay.data = RPL_AUTH_PASSED;
									writen(fd, (void *)&replay, sizeof(replay));
									printf("User Login successful\n");
									IS_CONNECTED(fd) = 2;
									start_thread(sock_thread_struct, &fd, &request_process);
									set_thread_priority(sock_thread_struct, VW_MAX_THREAD_PRIORITY - 1);
									break;
								} else {
									replay.data = RPL_AUTH_FALLED;
									writen(fd, (void *)&replay, sizeof(replay));
									tcp_close(fd);
									IS_CONNECTED(fd) = 0;
								}
							}
						}
					}
				}
			}
		}
	}

	for (fd = 0; fd < MAX_CONNECTED; fd ++) {
		IS_CONNECTED(fd) = 0;
	}
	tcp_close(listenfd);
	sleep(5);

	printf("Listen threa finish! \n");

	return 0;
}

int main() {
	int fd;
	fd = tcp_init(8888);
	Pthreadstruct smarthomestruct;
	start_thread(smarthomestruct, &fd, &smarthome);
	while (1) {
		sleet(1);
	}
	return 0;
}




























